<?php


namespace app\msgapi\service;

use app\dbtool\tableTool;
use app\utils\Date;
use app\msgapi\model\{Cust,
    GroupChat,
    HuihuaGroup,
    HuihuaMsg,
    HuihuaTables,
    SecretParam,
    SystemHeartbeat,
    User,
    UserCust,
    Sensitive};
use think\facade\{Cache, Db, Log};

error_reporting(E_ERROR | E_PARSE);
class HuihuaMsgService
{
    private $ym; //按月动态分表
    public function __construct()
    {
        $this->ym = date('Ym');
    }
    /**批量拉取存档数据并解密
     * @return bool|string
     * @throws \Exception
     */
    public function pullMsg()
    {
        //初始化数据
        $javaPullMsgApiService = new JavaPullMsgApiService();
        if(HuihuaTables::where('table_suffix','=',$this->ym)->count()){
            $seq = HuihuaMsg::suffix('_'.$this->ym)->order('seq desc')->value('seq');
        }
        if(!$seq){
            $table_suffix = HuihuaTables::where('table_suffix','<>',$this->ym)->order('id desc')->value('table_suffix');
            if($table_suffix) $seq = HuihuaMsg::suffix('_'.$table_suffix)->order('seq desc')->value('seq');
        }
        if(!$seq) $seq = 0;
        try {
            $initSdk = $javaPullMsgApiService->initSdk();
        }catch (\Exception $e)
        {
            SystemHeartbeat::update(['state'=>2,'errmsg'=>"初始化SDK失败",'add_time'=>date('Y-m-d H:i:s')],['id'=>1]); //系统心跳用
            Log::write('初始化SDK失败：' . json_encode($e->getMessage(), 256),'error');
            return false;
        }

        $limit = 100;
        $default_corpid = env('wework.corpid');
        $privateKeyInfo = SecretParam::where('cid', $default_corpid)->order('version desc')->value('private_key');
        if ($initSdk['code'] == 0) {
            do {
                $next = false;
                $list = $javaPullMsgApiService->getDecryptChatData($initSdk['data'], $seq, $privateKeyInfo, $limit);
                if ($list['code'] == 0) {//java返回结果，外面包了一层
                    $wxdata = json_decode($list['data'], true);//字符串转数组
                    if ($wxdata['errcode'] == 0) {//微信返回结果
                        if ($wxdata['chatdata']) {//如果有数据
                            $this->saveMsgList($wxdata['chatdata']);
                            $next = true;
                            $seq = max(array_column($wxdata['chatdata'], 'seq'));
                            if (count($wxdata['chatdata']) < $limit) {
                                $next = false;
                            }
                            //有数据拉取在存储中更新心跳,此处不需要
                        }else{
                            SystemHeartbeat::update(['state'=>1,'errmsg'=>"存档数据拉取正常",'add_time'=>date('Y-m-d H:i:s')],['id'=>1]); //系统心跳用,无数据拉取时用
                            Log::write('存档结果集为空','info');
                        }
                    }else{
                        SystemHeartbeat::update(['state'=>2,'errmsg'=>'获取存档数据失败.errcode：' . $wxdata['errcode'] . 'errmsg:' . $wxdata['errmsg'],'add_time'=>date('Y-m-d H:i:s')],['id'=>1]);
                        Log::write('获取存档数据失败.errcode：' . $wxdata['errcode'] . 'errmsg:' . $wxdata['errmsg'] ,'error');
                    }
                } else {
                    SystemHeartbeat::update(['state'=>2,'errmsg'=>"获取存档数据列表失败：".json_encode($list, 256),'add_time'=>date('Y-m-d H:i:s')],['id'=>1]); //系统心跳用
                    Log::write('获取存档数据列表失败：' . json_encode($list, 256),'error');
                }
            } while ($next);
        } else {
            SystemHeartbeat::update(['state'=>2,'errmsg'=>"初始化SDK失败：".json_encode($initSdk, 256),'add_time'=>date('Y-m-d H:i:s')],['id'=>1]); //系统心跳用
            Log::write('初始化SDK失败：' . json_encode($initSdk, 256),'error');
        }
        try {
            $return = $javaPullMsgApiService->destroySdk($initSdk['data']);
            $return['code'] == 0 ? : Log::write('销毁SDKID失败.code：' . $return['code'] . 'msg:' . $return['msg'] ,'error');
            return true;
        }catch (\Exception $e)
        {
            return '失败'.$e->getMessage();
        }
    }

    /**处理未解密的数据进行重新解密
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function redecreptdata()
    {
        ini_set('memory_limit', '-1');
        $private_list = SecretParam::where('cid', env('wework.corpid'))->column('private_key', 'version');

        //初始化SDK
        $javaPullMsgApiService = new JavaPullMsgApiService();
        $initsdk = $javaPullMsgApiService->initSdk();
        $msgbody = self::defaultMsgbody();
        $HuihuaMsg = new HuihuaMsg();
        if ($initsdk['code'] == 0) {
        //table_suffix
        $huihuaTables = HuihuaTables::where('isdecrtpt_all','=',0)->limit(1000)->select()->toArray();
        if($huihuaTables){
            foreach ($huihuaTables as $tables){
                if($tables['table_suffix']) $list  = HuihuaMsg::suffix('_'.$tables['table_suffix'])->where('isdecrtpt','=',0)->select()->toArray();
                if($list){
                    foreach ($list as $v) {
                        try {
                            $info = $javaPullMsgApiService->decryptDataByPk($initsdk['data'], $private_list[$v['publickey_ver']], $v['encrypt_random_key'], $v['encrypt_chat_msg']);
                            if ($info['code'] == 0) {
                                $data = json_decode($info['data'], true);
                                if($data){
                                    $val = [
                                        'isdecrtpt' => 1,
                                        'msgid' => $v['msgid'],
                                        'seq' => $v['seq'],
                                        'body' => $data,
                                        'publickey_ver' => '',
                                        'encrypt_chat_msg' => '',
                                        'encrypt_random_key' => ''
                                    ];
                                    try {
                                        $huihuaGroupService = new HuihuaGroupService();
                                        //组数据
                                        $groupId = $huihuaGroupService->saveGroupData($val['body']);
                                        //会话解密数据
                                        $msgData = $this->getDecreptData($val, $groupId, $msgbody);
                                        $msgData['publickey_ver'] = '';
                                        $msgData['encrypt_chat_msg'] = '';
                                        $msgData['encrypt_random_key'] = '';

                                        $HuihuaMsg->setSuffix('_'.strtolower($tables['table_suffix']))->where('id',$v['id'])->update($msgData); //这里不需要再更新表解密状态,下次任务执行会自动走else更新//会话消息撤回标记,优化撤回消息展示用
                                        if(($msgData['actionnm'] == 'recall') && $msgData['msgbody']){
                                            $msgbody_revoke = json_decode($msgData['msgbody'],true);
                                            if($msgbody_revoke['pre_msgid']) $HuihuaMsg->setSuffix('_'.strtolower($tables['table_suffix']))->where('msgid',$msgbody_revoke['pre_msgid'])->update(['is_revoke'=>$msgData['msgid']]);
                                        }
                                        //更新消息回复时间,即使报错也要跳过，不能影响正常的数据存储
                                        @self::upSendLastMsgTime($msgData);
                                        //订阅消息检查,即使报错也要跳过，不能影响正常的数据存储
                                        $sensitiveModel = new Sensitive();
                                        try {
                                            $sen = new HuihuaSensitiveService($sensitiveModel);
                                            @$sen->checkSensitive($msgData);
                                        } catch (\Exception $e) {
                                            Log::write('订阅消息(关键词)检查失败:' . json_encode($e->getMessage(), 256));
                                        }

                                    } catch (\Exception $e) {
                                        Log::write('[重新解密]存储失败id=' . $v['id'] . '失败原因:' . $e->getMessage(), 'error');
                                    }
                                }else{
                                    Log::write('[重新解密]无法解密：字符集错误', 'error');
                                }
                            } else {
                                Log::write('[重新解密]解密失败：' . json_encode($info, 256), 'error');
                            }
                        }catch (\Exception $e){
                            Log::write('[重新解密]jdk解密失败：' . $e->getMessage(), 'error');
                        }

                    }
                }else{
                    //跳过最新表的解密状态更新
                    if($tables['table_suffix'] == $this->ym) continue;
                    HuihuaTables::update(['isdecrtpt_all'=>1],['table_suffix'=>$tables['table_suffix']]);
                    Log::write('[重新解密]该表(后缀:'.$tables['table_suffix'].')暂无未解密数据,已更新为完成解密状态', 'info');

                }

            }
        }else{
            Log::write('会话存档记录表读取失败','error');
        }

        }else {
            Log::write('初始化SDK失败：' . json_encode($initsdk, 256),'error');
        }
        //销毁SDK
        $javaPullMsgApiService->destroySdk($initsdk['data']);
        return true;
    }


    /**保存数据到数据库
     * @param $data
     */
    public function saveMsgList($data)
    {
        $msgbody = self::defaultMsgbody();
        $huihuaGroupService = new HuihuaGroupService();
        $tableTool = new tableTool();
        $HuihuaMsg = new HuihuaMsg();
        foreach ($data as $val) {
            try {
                if ($val['isdecrtpt'] == 1) {//已解密
                    //按照月分表最多查两个表,会话存档最多拉取三天内的数据.查最新的表和上一个表即可
                    $huihua_tables = HuihuaTables::order('id desc')->limit(2)->select()->toArray();
                    $msg_count = 0;
                    if($huihua_tables){
                        foreach ($huihua_tables as $tables){
                            if($tables['table_suffix']) $msg_count += HuihuaMsg::suffix('_'.$tables['table_suffix'])->where('msgid', $val['body']['msgid'])->count();
                        }
                    }
                    if ($msg_count && $msg_count > 0) continue;
                    //组数据
                    $groupId = $huihuaGroupService->saveGroupData($val['body']);
                    //会话解密数据
                    $msgData = $this->getDecreptData($val, $groupId, $msgbody);
                } else {
                    //会话未解密数据
                    $msgData = $this->getUndereptData($val);
                }
                if ($msgData) {
                    $table_check = $tableTool->createTable($this->ym);
                    if($table_check){
                        $HuihuaMsg->setSuffix('_' . strtolower($this->ym))->insert($msgData);
//                        HuihuaMsg::create($msgData);
                        //会话消息撤回标记,优化撤回消息展示用
                        if(($msgData['actionnm'] == 'recall') && $msgData['msgbody']){
                            $msgbody_revoke = json_decode($msgData['msgbody'],true);
                            if($msgbody_revoke['pre_msgid']) $HuihuaMsg->setSuffix('_' . strtolower($this->ym))->where('msgid',$msgbody_revoke['pre_msgid'])->update(['is_revoke'=>$msgData['msgid']]);
                        }
                        //更新消息回复时间,即使报错也要跳过，不能影响正常的数据存储
                        @self::upSendLastMsgTime($msgData);
                        //订阅消息检查,即使报错也要跳过，不能影响正常的数据存储
                        $sensitiveModel = new Sensitive();
                        try {
                            $sen = new HuihuaSensitiveService($sensitiveModel);
                            @$sen->checkSensitive($msgData);
                        } catch (\Exception $e) {
                            Log::write('订阅消息(关键词)检查失败:' . json_encode($e->getMessage(), 256));
                        }
                    }else{
                        SystemHeartbeat::update(['state'=>3,'errmsg'=>'检查分表失败:数据存储不成功','add_time'=>date('Y-m-d H:i:s')],['id'=>1]);
                        Log::write('检查分表失败:数据存储不成功','error');
                    }
                }
                SystemHeartbeat::update(['state'=>1,'errmsg'=>"存档数据存储成功",'add_time'=>date('Y-m-d H:i:s')],['id'=>1]); //系统心跳用,有拉取数据的时候用
            } catch (\Exception $e) {
                SystemHeartbeat::update(['state'=>3,'errmsg'=>'会话存储失败:' . json_encode($e->getMessage() . ':' . $e->getLine(), 256),'add_time'=>date('Y-m-d H:i:s')],['id'=>1]);
                Log::write('会话存储失败:' . json_encode($e->getMessage() . ':' . $e->getLine(), 256));
            }
        }
    }
    /**更新消息回复时间(长时间未回复消息用)
     * @param $data
     * @return void
     * @throws \Throwable
     */
    public static function upSendLastMsgTime($data)
    {
        $user_lst = Cache::remember('useridlst', function(){
            return User::column('userid');
        },86400); //成员userid缓存
        if($data['fromid'] && $data['hs_group_id'] && $data['msgtime']){
            if(in_array($data['fromid'],$user_lst)){ //是成员,这里需要更新消息最后一次更新时间
                HuihuaGroup::update(['user_last_send_time'=>strtotime($data['msgtime']),'msg_last_up_time'=>time()],['id'=>$data['hs_group_id']]);
            }else{ //是客户或者其他非成员,这里需要更新消息最后一次更新时间
                HuihuaGroup::update(['cust_last_send_time'=>strtotime($data['msgtime']),'msg_last_up_time'=>time()],['id'=>$data['hs_group_id']]);
            }
        }
    }

    /**获取解密成功后的的存库数据
     * @param $val
     * @return array|false
     * @throws \think\Exception
     */
    public function getDecreptData($val, $groupId, $msgbody)
    {
        $msgInfo = $val['body'];
        //切换企业时，重新解密返回的时间字段不是msgtime 而是time
        isset($msgInfo['msgtime']) ? : $msgInfo['msgtime'] = $msgInfo['time'];
        $msgData = [
            'isdecrtpt' => $val['isdecrtpt'],
            'seq' => $val['seq'],
            'msgid' => $val['msgid'],
            'mstype' => $msgInfo['msgtype']??NULL,
            'msgbody' => (isset($msgInfo['msgtype']) && $msgInfo['msgtype']) ? json_encode($msgInfo[$msgbody[$msgInfo['msgtype']]], 256) : NULL,
            'content' => (isset($msgInfo['msgtype']) && $msgInfo['msgtype'] == 'text') ? $msgInfo['text']['content'] : '',
            'actionnm' => $msgInfo['action']??NULL,
            'fromid' => (isset($msgInfo['from']) && ($msgInfo['from'] !== null)) ? $msgInfo['from'] : $msgInfo['user'],
            'tolist' => (isset($msgInfo['tolist']) && $msgInfo['tolist']) ? implode(',', $msgInfo['tolist']) : NULL,
            'hs_group_id' => $groupId,
            'roomid' => $msgInfo['roomid']??NULL,
            'msgtime' => date('Y-m-d H:i:s', $msgInfo['msgtime'] / 1000),
            'sdkfileid' => $msgInfo['file']['sdkfileid']??NULL,
            'filepath' => '',
//            'typenu' => $msgInfo['voiceid']??NULL,
            'isgetfile' => (isset($msgInfo['msgtype']) && $msgInfo['msgtype']) ? $this->checkgetfile($msgInfo[$msgbody[$msgInfo['msgtype']]]) : 0,
        ];
        if(isset($msgInfo['action']) && $msgInfo['action'] == 'switch') return $msgData; //切换企业消息不需要走后面
        $userModel = new User();
        $custModel = new Cust();
        $userCustModel = new UserCust();
        if (isset($msgInfo['roomid']) && $msgInfo['roomid']) {
            //处理群组信息，数据库中存在，则不处理，不存在则需要进行新增操作
            $huihuaGroupChatService = new HuihuaGroupChatService();
            $huihuaGroupChatService->queryGroupInfo($msgInfo['roomid'], 0);
        } else {
            $cust = new HuihuaCustService($custModel, $userModel, $userCustModel);
            $cust->queryExternalInfo($msgData['fromid'], $msgInfo['tolist'], 0);
        }
        //'会话记录'消息单独判断是否需要获取文件
        if (isset($msgInfo['msgtype']) && $msgInfo['msgtype'] == 'chatrecord') {
            $files = [];
            $this->msgbodyToArray(json_encode($msgInfo[$msgbody[$msgInfo['msgtype']]], 256), $files);
            $msgData['filelist'] = json_encode($files, 256);
            if ($files) {
                $msgData['isgetfile'] = 1;
            } else {
                $msgData['isgetfile'] = 0;
            }
        }

        return $msgData;
    }

    /**解密失败，获取相关数据，存储，用于后续重新解密
     * @param $val
     * @return array
     */
    public function getUndereptData($val)
    {
        $msgData = [
            'isdecrtpt' => $val['isdecrtpt'],
            'publickey_ver' => $val['publickey_ver'],
            'encrypt_chat_msg' => $val['encrypt_chat_msg'],
            'msgid' => $val['msgid'],
            'encrypt_random_key' => $val['encrypt_random_key'],
            'seq' => $val['seq']
        ];
        return $msgData;
    }

    /**检查消息是否需要获取文件。1需要0不需要
     * @param $info
     * @return int
     */
    public function checkgetfile($info)
    {
        if (isset($info['sdkfileid'])) {
            return 1;
        }
        if (isset($info['item'])) {
            foreach ($info['item'] as $val) {
                if (json_decode($val['content'], true)['sdkfileid']) {
                    return 1;
                }
            }
        }
        return 0;
    }

    /**会话记录消息时，获取所有需要获取文件的信息{md5:{sdkfileid,fileext}}
     * @param $body
     * @param array $files
     */
    public function msgbodyToArray($body, &$files = [])
    {
        $emotion_type = [1 => 'gif', 2 => 'png'];
        $file_ext = ['ChatRecordImage' => 'png', 'ChatRecordVideo' => 'mp4'];
        $body = json_decode($body, true);
        foreach ($body['item'] as $v) {
            if ($v['type'] == 'chatrecord') {
                $this->msgbodyToArray($v['content'], $files);
            }
            $v['content'] = json_decode($v['content'], true);
            if (isset($v['content']['md5sum'])) {
                $v['content']['fileext'] ? $filext = $v['content']['fileext'] : $filext = $file_ext[$v['type']];
                $files[$v['content']['md5sum']] = ['msgtime' => $v['msgtime'], 'sdkfileid' => $v['content']['sdkfileid'], 'fileext' => $filext];
            }
            if ($v['type'] == 'ChatRecordMixed') {
                foreach ($v['content']['item'] as $v1) {
                    if (in_array($v1['type'], ['image', 'emotion'])) {
                        $v1['content'] = json_decode($v1['content'], true);
                        $type = ['image' => 'png', 'emotion' => $emotion_type[$v1['content']['type']]];
                        if (isset($v1['content']['md5sum'])) {
                            $files[$v1['content']['md5sum']] = ['msgtime' => $v['msgtime'], 'sdkfileid' => $v1['content']['sdkfileid'], 'fileext' => $type[$v1['type']]];
                        }
                    }
                }
            }
        }
    }

    /**获取年度数据按照周分组
     * @param $data
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getYearData($data){
        $year = $data['year'] ?? date('Y');
        //查询所有记录表,已根据数据验证过统计出来是准确的
        $tables_where[] = ['table_suffix','between',[$year.'01',$year.'12']];
        $huihua_tables = HuihuaTables::where($tables_where)->order('id desc')->select()->toArray();
        $field = "WEEK(msgtime) as week,id,msgtime";
        if(!$huihua_tables) return [];
        $where[] = ['msgtime','between',[$year.'-01-01 00:00:00',$year.'-12-31 23:59:59']];
        $first_table_suffix = $huihua_tables[0]['table_suffix'];
        $firstsql = HuihuaMsg::suffix("_$first_table_suffix")->field($field)->where($where);

        foreach ($huihua_tables as $k => $tables)
        {
            if($k == 0) continue; //跳过第一个表
            $sql = HuihuaMsg::suffix("_{$tables['table_suffix']}")->field($field)->where($where)->buildSql();
            $firstsql = $firstsql->unionAll($sql);
        }
        $firstsql =  $firstsql->buildSql();
        $list = Db::table($firstsql . 'as msg')->field("msg.week,count(msg.id) as count")->order("msg.msgtime asc")->group("WEEK(msg.msgtime)")->select()->toArray();
        return $list;
    }

    /**文件下载
     * @return bool|string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getMsgFile()
    {
        //查询所有记录表
        $huihua_tables = HuihuaTables::order('id desc')->select()->toArray();
        if(!$huihua_tables) return false;
        //初始化数据
        $javaPullMsgApiService = new JavaPullMsgApiService();
        $initSdk = $javaPullMsgApiService->initSdk();
        if($initSdk['code'] == 0){
            $fileHandle = new FileHandleService();
            foreach ($huihua_tables as $tables)
            {
                $need_downloads = HuihuaMsg::suffix('_'.$tables['table_suffix'])->where('isgetfile','=',1)->select()->toArray();
                foreach ($need_downloads as $v)
                {
                    //避免重复，拉取前校验一次数据
                    try {
                        $isgetfile = HuihuaMsg::suffix('_'.$tables['table_suffix'])->where('id',$v['id'])->value('isgetfile');
                        if ($isgetfile != 1) continue;
                        //设置文件拉取中
                        HuihuaMsg::suffix('_'.$tables['table_suffix'])->where('id',$v['id'])->update(['isgetfile' => 2]);
                        $res = $fileHandle->fileDown($initSdk['data'], $v, env('filedir.file_default_dir'));
                        if ($res) {
                            HuihuaMsg::suffix('_'.$tables['table_suffix'])->where('id',$v['id'])->update($res);
                        }else{
                            //拉取失败设置文件未拉取(防止文件拉取失败,$res直接返回isgetfile=3)
                            HuihuaMsg::suffix('_'.$tables['table_suffix'])->where('id',$v['id'])->update(['isgetfile' => 1]);
                        }
                    } catch (\Exception $e) {
                        HuihuaMsg::suffix('_'.$tables['table_suffix'])->where('id',$v['id'])->update(['isgetfile' => 1]);
                        Log::write('[文件拉取]table_suffix:'.$tables['table_suffix'].'msgid:' . $v['msgid'] . '拉取文件失败,原因:'.$e->getMessage().',数据状态已回退');
                    }
                }
            }
        }else {
            Log::write('[文件拉取]初始化SDK失败：' . json_encode($initSdk, 256),'error');
        }
        try {
            $return = $javaPullMsgApiService->destroySdk($initSdk['data']);
            $return['code'] == 0 ? : Log::write('[文件拉取]销毁SDKID失败.code：' . $return['code'] . 'msg:' . $return['msg'] ,'error');
            return true;
        }catch (\Exception $e)
        {
            return '失败'.$e->getMessage();
        }
    }


    /**会话消息类型对应消息体键名
     * @return string[]
     */
    public static function defaultMsgbody()
    {
        $default_msgbody = [
            'text' => 'text',//文本消息
            'image' => 'image',//图片消息
            'revoke' => 'revoke',//撤回消息
            'disagree' => 'disagree',//不同意会话存档
            'agree' => 'agree',//同意会话存档
            'voice' => 'voice',//语音消息
            'video' => 'video',//视频消息
            'card' => 'card',//名片
            'location' => 'location',//位置
            'emotion' => 'emotion',//表情
            'file' => 'file',//文件
            'link' => 'link',//链接
            'weapp' => 'weapp',//小程序
            'chatrecord' => 'chatrecord',//会话记录消息
            'collect' => 'collect',//填表
            'redpacket' => 'redpacket',//红包
            'meeting' => 'meeting',//会议
            'docmsg' => 'doc',//在线文档
            'markdown' => 'info',//MarkDown格式消息
            'news' => 'info',//图文消息
            'calendar' => 'calendar',//日程消息
            'mixed' => 'mixed',//混合消息
            'meeting_voice_call' => 'meeting_voice_call',//音频存档消息
            'voiptext' => 'voiptext',//视频频存档消息
            'voip_doc_share' => 'voip_doc_share',//音频共享文档消息
            'external_redpacket' => 'redpacket',//互通红包消息
            'sphfeed' => 'sphfeed',//视频号消息
            'todo' => 'todo',//待办
            'vote' => 'vote',//投票
        ];
        return  $default_msgbody;
    }

    /**获取指定成员聊天对象列表
     * @param $data
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getMemberChatObject($data,$admin_groupid,$adminid)
    {
        $limit = $data['limit']?:config('page.defaule_limit');
        if(!isset($data['userid']) || !$data['userid']) return error_json('成员userid参数错误');
        //授权范围权限判断,只需要控制该接口即可.
        $hsorganizationService = new HsorganizationService();
        $auth_user_arr = $hsorganizationService->getDepartmentLst(2,0,$admin_groupid,$adminid);
        if($auth_user_arr !== 'all'){ //超管(all)跳过
            if(!in_array($data['userid'],$auth_user_arr)) return error_json('暂无该成员权限');
        }
        $userid = $data['userid'];
        $cust_id = $data['cust_id'] ?? '';
        $title = $data['title'] ?? '';
        $is_crowd = $data['is_crowd'] ?? 0;
        $chat_id = $data['chat_id'];

        $order = 'hg.update_time desc';
        if ($data['order']) {
            $order = 'hg.'.$data['order'].' '.($data['sort']?:'desc');
        }
        if ($is_crowd == 0) {
            $cust = new Cust();
            $user = new User();
            //获取客户
            if($cust_id){
                $searchcust = $cust->where('id', '=', $cust_id)->value('external_userid');
                if($searchcust){
                    $where[] = "(FIND_IN_SET('{$searchcust}',`userlist`))";
                }
            }else{
                if ($title) {
                    $searchcust = $cust->where('name', 'like', "%{$title}%")->column('external_userid');
                    $searchstaff = $user->where('userid','<>',$userid)->where('name', 'like', "%{$title}%")->column('userid');
                    $searchuser = array_merge($searchcust, $searchstaff);
                    foreach ($searchuser as $val) {
                        $where[] = "(FIND_IN_SET('{$val}',`userlist`))";
                    }
                }
            }
            $list = HuihuaGroup::alias('hg');
            if($title||$cust_id){
                if($where){
                    $list = $list->where(implode(' OR ',$where));
                }else{
                    $list = $list->where('id','<',0);
                }
            }
            $list = $list->where("FIND_IN_SET('{$userid}',`userlist`)")
                ->where([['is_crowd','=',$is_crowd]])
                ->withAttr('userlist', function ($item) use ($userid) {
                    $ulist = explode(',', $item);
                    if ($ulist[0] == $userid) return $ulist[1];
                    return $ulist[0];
                })
                ->order($order)
                ->paginate($limit)->toArray();
            //将所有的成员id组成集合，然后分别从客户表和用户表获取对应的成员信息。用于前端展示用户信息
            $userList = implode(',', array_column($list['data'], 'userlist'));
            $custlist = $cust->where('external_userid', 'in', $userList)->select()->toArray();
            $userobj = [];
            foreach ($custlist as $val) {
                $userobj[$val['external_userid']] = ['name' => $val['name'], 'avatar' => $val['avatar'], 'type' => $val['type'], 'corp_name' => $val['corp_name']];
            }
            $userlist = $user->where('userid', 'in', $userList)->select()->toArray();
            foreach ($userlist as $val) {
                $userobj[$val['userid']] = ['name' => $val['name'], 'avatar' => $val['avatar'], 'type' => 3];
            }
            $list['userinfo'] = $userobj;
            return success_json('成功',$list);
        } else {
            $list = HuihuaGroup::field('hg.*,gc.name,gc.type as group_type')
                ->alias('hg')
                ->join('group_chat gc', 'gc.chat_id = hg.chatid', 'left');
            if($chat_id){
                $list = $list->where('gc.chat_id','=', $chat_id);
            }else{
                if($title) $list = $list->where([['gc.name','like',"%{$title}%"]]);
            }
            $list = $list->where([['hg.is_crowd','=',$is_crowd]])
                ->where("FIND_IN_SET('{$userid}',`userlist`)")
                ->order($order)
                ->paginate($limit)->toArray();
            return success_json('成功',$list);
        }
    }

    /**获取指定聊天对象聊天记录
     * @param $data
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getChatLst($data,$admin_groupid,$adminid)
    {
        $limit = $data['limit']?:config('page.defaule_limit');
        if($data['groupchat_chatid']) $data['group_id'] = HuihuaGroup::where('chatid','=',$data['groupchat_chatid'])->value('id'); //侧边栏群聊进入用
        if(!$data['group_id']) return error_json('参数错误');
        $group_id = $data['group_id'];
        $type = $data['msgtype'] ?? 'all';
        $types = [];
        switch ($type) {
            case 'text':
                $types[] = 'text';
                break;
            case 'image':
                $types[] = 'image';
                break;
            case "media":
                $types = ['video', 'voice'];
                break;
            case 'video_call':
                $types = ['meeting_voice_call', 'voip_doc_share','voiptext'];
                break;
            case "file":
                $types[] = 'file';
                break;
            case 'wxapp':
                $types[] = 'weapp';
                break;
        }
        if($data['start_time']) $data['start_time'] = date('Y-m-d',strtotime($data['start_time'])) . ' 00:00:00';
        if($data['end_time']) $data['end_time'] = date('Y-m-d',strtotime($data['end_time'])) . ' 23:59:59';
        //有权限的所有成员
        $hsorganizationService = new HsorganizationService();
        $auth_user_arr = $hsorganizationService->getDepartmentLst(2,0,$admin_groupid,$adminid);
        if(($auth_user_arr !== 'all') && empty($auth_user_arr)) return error_json('暂无成员权限');
        //查询所有记录表
        $huihua_tables = HuihuaTables::order('id desc')->select()->toArray();
        if(!$huihua_tables) return error_json('记录表查询为空');
        if($huihua_tables) {
            $first_table_suffix = $huihua_tables[0]['table_suffix'];
            //成员权限
            if(($auth_user_arr !== 'all') && !empty($auth_user_arr) ){
                foreach ($auth_user_arr as $au_user)
                {
                    $whereOr_first[] = "FIND_IN_SET('{$au_user}',msg_$first_table_suffix.`tolist`)";
                    $whereOr_first[] = "msg_$first_table_suffix.fromid = '{$au_user}'";
                }
            }

            $firstsql = HuihuaMsg::suffix("_$first_table_suffix")
                ->field("msg_$first_table_suffix.*,user.name as u_name,user.avatar as u_avatar,cust.name as c_name,cust.avatar as c_avatar")
                ->alias("msg_$first_table_suffix")
                ->where("hs_group_id", $group_id);
            if(isset($whereOr_first)) $firstsql = $firstsql->where(implode(' OR ',$whereOr_first));//成员权限

            $firstwhere = [];
            $data['keyword'] && $firstwhere[] = ["msg_$first_table_suffix.msgbody", "like", "%{$data['keyword']}%"];
            ($data['start_time'] && $data['end_time']) && $firstwhere[] = ["msg_$first_table_suffix.msgtime", "between", [trim($data['start_time']), trim($data['end_time'])]];
            (!$data['start_time'] && $data['end_time']) && $firstwhere[] = ["msg_$first_table_suffix", "<=", trim($data['end_time'])];
            ($data['start_time'] && !$data['end_time']) && $firstwhere[] = ["msg_$first_table_suffix", ">=", trim($data['start_time'])];
            $firstwhere[] = ["msg_$first_table_suffix.actionnm", "<>", "recall"]; //不查询消息动作为撤回消息的消息类型,因为撤回消息已在拉取消息时处理过了
            !empty($types) && $firstwhere[] = ["msg_$first_table_suffix.mstype", "in", $types];
            $firstsql = $firstsql->where($firstwhere)
                ->join("user user", "msg_$first_table_suffix.fromid = user.userid", "left")
                ->join("cust cust", "cust.external_userid = msg_$first_table_suffix.fromid", "left");

            foreach ($huihua_tables as $k => $tables) {
                if ($k == 0) continue; //跳过第一个表
                $whereOr_other = []; $where = [];
                //成员权限
                if(($auth_user_arr !== 'all') && !empty($auth_user_arr) ){
                    foreach ($auth_user_arr as $au_user_suffix)
                    {
                        $whereOr_other[] = "FIND_IN_SET('{$au_user_suffix}',msg_{$tables['table_suffix']}.`tolist`)";
                        $whereOr_other[] = "msg_{$tables['table_suffix']}.fromid = '{$au_user_suffix}'";
                    }
                }
                $data['keyword'] && $where[] = ["msg_{$tables['table_suffix']}.msgbody", "like", "%{$data['keyword']}%"];
                ($data['start_time'] && $data['end_time']) && $where[] = ["msg_{$tables['table_suffix']}.msgtime", "between", [trim($data['start_time']), trim($data['end_time'])]];
                (!$data['start_time'] && $data['end_time']) && $where[] = ["msg_{$tables['table_suffix']}", "<=", trim($data['end_time'])];
                ($data['start_time'] && !$data['end_time']) && $where[] = ["msg_{$tables['table_suffix']}", ">=", trim($data['start_time'])];
                $where[] = ["msg_{$tables['table_suffix']}.actionnm", "<>", "recall"]; //不查询消息动作为撤回消息的消息类型,因为撤回消息已在拉取消息时处理过了
                !empty($types) && $where[] = ["msg_{$tables['table_suffix']}.mstype", "in", $types];
                $sql = HuihuaMsg::suffix("_{$tables['table_suffix']}")
                    ->field("msg_{$tables['table_suffix']}.*,user$k.name as u_name,user$k.avatar as u_avatar,cust$k.name as c_name,cust$k.avatar as c_avatar")
                    ->alias("msg_{$tables['table_suffix']}")
                    ->where("hs_group_id", $group_id)
                    ->where($where);
                if(!empty($whereOr_other)) $sql = $sql->where(implode(' OR ',$whereOr_other)); //成员权限
                $sql = $sql->join("user user$k", "msg_{$tables['table_suffix']}.fromid = user$k.userid", "left")
                    ->join("cust cust$k", "cust$k.external_userid = msg_{$tables['table_suffix']}.fromid", "left")
                    ->buildSql();
                $firstsql = $firstsql->unionAll($sql);
            }

            $firstsql = $firstsql->buildSql();
            $order = "msg.msgtime desc";
            if ($data['order']) {
                $order = "msg." . $data['order'] . ' ' . ($data['sort'] ?: 'desc');
            }
            //dd(Db::table("$firstsql as msg")->order($order)->buildSql());
            if($data['is_output'] == 1){ //导出
                //成员userid=>name
                $user_for_name = User::column('name','userid');
                //客户external_userid=>name
                $external_userid_for_name = Cust::column('name','external_userid');
                //群聊chat_id=>name
                $chat_id_for_name = GroupChat::column('name','chat_id');
                //超出一个月(90天)不能导出
                if(!$data['start_time'] || !$data['end_time']) return error_json('请选择时间范围【90天以内】');
                $days = Date::diffBetweenTwoDays($data['start_time'],$data['end_time']);
                if(round($days,2) > 90){return error_json("超出时间导出范围");}
                $list = Db::table("$firstsql as msg")->order($order)->select()->toArray();

                header("Content-Type:application/download");
                header('Content-Disposition:attachment;filename="' . date('YmdHis') . '.csv"');
                echo "\xEF\xBB\xBF"; // UTF-8 BOM 防止windows系统的wps打开中文乱码
                ob_clean();//清除第一行空白
                $fp = fopen('php://output', 'a');//打开output流
                $title = ['ID','消息类型','消息体','文本消息内容','消息动作','消息发送方','消息接收方','消息发送时间'];
                mb_convert_variables('GBK', 'UTF-8', $title);
                fputcsv($fp, $title);//将数据格式化为csv格式并写入到output流中

                $mstype = ['text'=>'文本','image'=>'图片','media'=>'录音/视频','video_call'=>'语音通话','file'=>'文件','wxapp'=>'小程序'];
                $actionnm = ['send'=>'发送消息','recall'=>'撤回消息','switch'=>'切换企业日志'];
                foreach ($list as $v){
                    $fromid = ''; $tolist='';
                    if(isset($user_for_name[$v['fromid']])){
                        $fromid = $user_for_name[$v['fromid']];
                    }elseif (isset($external_userid_for_name[$v['fromid']])){
                        $fromid = $external_userid_for_name[$v['fromid']];
                    }
                    if($v['roomid']){ //群聊
                        $tolist = $chat_id_for_name[$v['roomid']] ?: '群聊';
                    }else{ //单聊
                        $tolist = '';
                        if(isset($user_for_name[$v['tolist']])){
                            $tolist = $user_for_name[$v['tolist']];
                        }elseif (isset($external_userid_for_name[$v['tolist']])){
                            $tolist = $external_userid_for_name[$v['tolist']];
                        }
                    }
                    $tmp_v = [];
                    $tmp_v[] = $v['id']?:" ";
                    $tmp_v[] = $mstype[$v['mstype']]?:" ";
                    $tmp_v[] = $v['msgbody']?:" ";
                    $tmp_v[] = $v['content']?:" ";
                    $tmp_v[] = $actionnm[$v['actionnm']]?:" ";
                    $tmp_v[] = $fromid?:" ";
                    $tmp_v[] = $tolist?:" ";
                    $tmp_v[] = $v['msgtime']?:" ";
                    mb_convert_variables('GBK', 'UTF-8', $tmp_v);
                    fputcsv($fp, $tmp_v);//将数据格式化为csv格式并写入到output流中
                }
                ob_flush();
                flush();//刷新输出缓冲到浏览器，使用效果是可以立即关闭新开页面，不用等待，只需要等待下载即可
                fclose($fp);
            }else{
                $list = Db::table("$firstsql as msg")->order($order)->paginate($limit)->toArray();
                return success_json('成功',$list);
            }
        }

    }

    /**消息审计列表
     * @param $data
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getChatAuditLst($data,$admin_groupid,$adminid)
    {
        $limit = $data['limit']?:config('page.defaule_limit');
        $type = $data['msgtype'] ?? 'all';
        $types = [];
        switch ($type) {
            case 'text':
                $types[] = 'text';
                break;
            case 'image':
                $types[] = 'image';
                break;
            case "media":
                $types = ['video', 'voice'];
                break;
            case 'video_call':
                $types = ['meeting_voice_call', 'voip_doc_share','voiptext'];
                break;
            case "file":
                $types[] = 'file';
                break;
            case 'wxapp':
                $types[] = 'weapp';
                break;
        }
        if(!$data['start_time'] && !$data['end_time']) {
            $data['start_time'] = date('Y-m-01');
            $data['end_time'] = date('Y-m-d');
        }
        if($data['start_time']) $data['start_time'] = date('Y-m-d',strtotime($data['start_time'])) . ' 00:00:00';
        if($data['end_time']) $data['end_time'] = date('Y-m-d',strtotime($data['end_time'])) . ' 23:59:59';
        $days = Date::diffBetweenTwoDays($data['start_time'], $data['end_time']);
        if(round($days, 2) > 90) {return error_json('超出时间查询范围(90天)');}
        //有权限的所有成员
        $hsorganizationService = new HsorganizationService();
        $auth_user_arr = $hsorganizationService->getDepartmentLst(2,0,$admin_groupid,$adminid);
        if(($auth_user_arr !== 'all') && empty($auth_user_arr)) return error_json('暂无成员权限');
        //查询所有记录表
        $huihua_tables = HuihuaTables::order('id desc')->select()->toArray();
        if(!$huihua_tables) return error_json('记录表查询为空');

        if($huihua_tables){
            $first_table_suffix = $huihua_tables[0]['table_suffix'];
            //成员权限
            if(($auth_user_arr !== 'all') && !empty($auth_user_arr) ){
                foreach ($auth_user_arr as $au_user)
                {
                    $whereOr_first[] = "FIND_IN_SET('{$au_user}',msg_$first_table_suffix.`tolist`)";
                    $whereOr_first[] = "msg_$first_table_suffix.fromid = '{$au_user}'";
                }
            }
            $firstsql = HuihuaMsg::suffix("_$first_table_suffix")
                ->field("msg_$first_table_suffix.id,msg_$first_table_suffix.msgbody,msg_$first_table_suffix.msgid,msg_$first_table_suffix.content,msg_$first_table_suffix.actionnm,msg_$first_table_suffix.fromid,msg_$first_table_suffix.roomid,msg_$first_table_suffix.tolist,msg_$first_table_suffix.mstype,msg_$first_table_suffix.filepath,msg_$first_table_suffix.msgtime,cust.avatar as c_avatar,cust.name as c_name,user.avatar as u_avatar,user.name as u_name,group.name as group_name,group.chat_id as group_id")
                ->alias("msg_$first_table_suffix");
            $firstwhere = [];
            if ($data['keyword']) {
                if ($data['gettype'] == 'in') {
                    $data['keyword'] && $firstwhere[] = ["msg_$first_table_suffix.msgbody", "like", "%{$data['keyword']}%"];
                } else if ($data['gettype'] === 'notin') {
                    $data['keyword'] && $firstwhere[] = ["msg_$first_table_suffix.msgbody", "not like", "%{$data['keyword']}%"];
                }
            }
            ($data['start_time'] && $data['end_time']) && $firstwhere[] = ["msg_$first_table_suffix.msgtime", "between", [trim($data['start_time']), trim($data['end_time'])]];
            (!$data['start_time'] && $data['end_time']) && $firstwhere[] = ["msg_$first_table_suffix.msgtime", "<=", trim($data['end_time'])];
            ($data['start_time'] && !$data['end_time']) && $firstwhere[] = ["msg_$first_table_suffix.msgtime", ">=", trim($data['start_time'])];
//            $data['userid'] && $firstwhere[] = ["msg_$first_table_suffix.fromid", "=", $data['userid']];
            $firstwhere[] = ["msg_$first_table_suffix.actionnm", "<>", "recall"]; //不查询消息动作为撤回消息的消息类型,因为撤回消息已在拉取消息时处理过了
            !empty($types) && $firstwhere[] = ["msg_$first_table_suffix.mstype", "in", $types];
            $firstsql = $firstsql->where($firstwhere);
            $data['userid'] && $firstsql = $firstsql->where("FIND_IN_SET('{$data['userid']}',msg_$first_table_suffix.`tolist`) OR msg_$first_table_suffix.`fromid` = '{$data['userid']}'");
            if(isset($whereOr_first)) $firstsql = $firstsql->where(implode(' OR ',$whereOr_first));//成员权限
            $firstsql = $firstsql->join("huihua_group hg", "hg.id = msg_$first_table_suffix.hs_group_id")
                ->join("group_chat group", "group.chat_id = hg.chatid", "left")
                ->join("user user", "msg_$first_table_suffix.fromid = user.userid", "left")
                ->join("cust cust", "cust.external_userid = msg_$first_table_suffix.fromid", "left");
            foreach ($huihua_tables as $k =>$tables)
            {
                if($k == 0) continue; //跳过第一个表
                $whereOr_other = []; $where = [];
                //成员权限
                if(($auth_user_arr !== 'all') && !empty($auth_user_arr) ){
                    foreach ($auth_user_arr as $au_user_suffix)
                    {
                        $whereOr_other[] = "FIND_IN_SET('{$au_user_suffix}',msg_{$tables['table_suffix']}.`tolist`)";
                        $whereOr_other[] = "msg_{$tables['table_suffix']}.fromid = '{$au_user_suffix}'";
                    }
                }
                if ($data['keyword']) {
                    if ($data['gettype'] == 'in') {
                        $data['keyword'] && $where[] = ["msg_{$tables['table_suffix']}.msgbody", "like", "%{$data['keyword']}%"];
                    } else if ($data['gettype'] == 'notin') {
                        $data['keyword'] && $where[] = ["msg_{$tables['table_suffix']}.msgbody", "not like", "%{$data['keyword']}%"];
                    }
                }
                ($data['start_time'] && $data['end_time']) && $where[] = ["msg_{$tables['table_suffix']}.msgtime", "between", [trim($data['start_time']), trim($data['end_time'])]];
                (!$data['start_time'] && $data['end_time']) && $where[] = ["msg_{$tables['table_suffix']}.msgtime", "<=", trim($data['end_time'])];
                ($data['start_time'] && !$data['end_time']) && $where[] = ["msg_{$tables['table_suffix']}.msgtime", ">=", trim($data['start_time'])];
//                $data['userid'] && $where[] = ["msg_{$tables['table_suffix']}.fromid", "=", $data['userid']];
                $where[] = ["msg_{$tables['table_suffix']}.actionnm", "<>", "recall"]; //不查询消息动作为撤回消息的消息类型,因为撤回消息已在拉取消息时处理过了
                !empty($types) && $where[] = ["msg_{$tables['table_suffix']}.mstype", "in", $types];
                $sql = HuihuaMsg::suffix("_{$tables['table_suffix']}")
                    ->field("msg_{$tables['table_suffix']}.id,msg_{$tables['table_suffix']}.msgbody,msg_{$tables['table_suffix']}.msgid,msg_{$tables['table_suffix']}.content,msg_{$tables['table_suffix']}.actionnm,msg_{$tables['table_suffix']}.fromid,msg_{$tables['table_suffix']}.roomid,msg_{$tables['table_suffix']}.tolist,msg_{$tables['table_suffix']}.mstype,msg_{$tables['table_suffix']}.filepath,msg_{$tables['table_suffix']}.msgtime,cust$k.avatar as c_avatar,cust$k.name as c_name,user$k.avatar as u_avatar,user$k.name as u_name,group$k.name as group_name,group$k.chat_id as group_id")
                    ->alias("msg_{$tables['table_suffix']}")
                    ->where($where);
                $data['userid'] && $sql = $sql->where("FIND_IN_SET('{$data['userid']}',msg_{$tables['table_suffix']}.`tolist`) OR msg_{$tables['table_suffix']}.`fromid` = '{$data['userid']}'");
                if(!empty($whereOr_other)) $sql = $sql->where(implode(' OR ',$whereOr_other)); //成员权限
                $sql = $sql->join("huihua_group hg$k", "hg$k.id = msg_{$tables['table_suffix']}.hs_group_id")
                    ->join("group_chat group$k", "group$k.chat_id = hg$k.chatid", "left")
                    ->join("user user$k", "msg_{$tables['table_suffix']}.fromid = user$k.userid", "left")
                    ->join("cust cust$k", "cust$k.external_userid = msg_{$tables['table_suffix']}.fromid", "left")
                    ->buildSql();
                $firstsql = $firstsql->unionAll($sql);
            }
            $firstsql =  $firstsql->buildSql();
            $order = "msg.msgtime desc";
            if ($data['order']) {
                $order = 'msg.'.$data['order'].' '.($data['sort']?:'desc');
            }

            if($data['is_output'] == 1){ //导出
                //成员userid=>name
                $user_for_name = User::column('name','userid');
                //客户external_userid=>name
                $external_userid_for_name = Cust::column('name','external_userid');
                //群聊chat_id=>name
                $chat_id_for_name = GroupChat::column('name','chat_id');
                //超出一个月(31天)不能导出
                if(!$data['start_time'] || !$data['end_time']) return error_json('请选择时间范围【31天以内】');
                $days = Date::diffBetweenTwoDays($data['start_time'],$data['end_time']);
                if(round($days,2) > 31){return error_json("超出时间导出范围");}
                $list = Db::table("$firstsql as msg")->order($order)->select()->toArray();
                header("Content-Type:application/download");
                header('Content-Disposition:attachment;filename="' . date('YmdHis') . '.csv"');
                echo "\xEF\xBB\xBF"; // UTF-8 BOM 防止windows系统的wps打开中文乱码
                ob_clean();//清除第一行空白
                $fp = fopen('php://output', 'a');//打开output流
                $title = ['ID','消息类型','消息体','文本消息内容','消息动作','消息发送方','消息接收方','消息发送时间'];
                mb_convert_variables('GBK', 'UTF-8', $title);
                fputcsv($fp, $title);//将数据格式化为csv格式并写入到output流中

                $mstype = ['text'=>'文本','image'=>'图片','media'=>'录音/视频','video_call'=>'语音通话','file'=>'文件','wxapp'=>'小程序'];
                $actionnm = ['send'=>'发送消息','recall'=>'撤回消息','switch'=>'切换企业日志'];
                foreach ($list as $v){
                    $fromid = ''; $tolist='';
                    if(isset($user_for_name[$v['fromid']])){
                        $fromid = $user_for_name[$v['fromid']];
                    }elseif (isset($external_userid_for_name[$v['fromid']])){
                        $fromid = $external_userid_for_name[$v['fromid']];
                    }
                    if($v['roomid']){ //群聊
                        $tolist = $chat_id_for_name[$v['roomid']] ?: '群聊';
                    }else{ //单聊
                        $tolist = '';
                        if(isset($user_for_name[$v['tolist']])){
                            $tolist = $user_for_name[$v['tolist']];
                        }elseif (isset($external_userid_for_name[$v['tolist']])){
                            $tolist = $external_userid_for_name[$v['tolist']];
                        }
                    }
                    $tmp_v = [];
                    $tmp_v[] = $v['id']?:" ";
                    $tmp_v[] = $mstype[$v['mstype']]?:" ";
                    $tmp_v[] = $v['msgbody']?:" ";
                    $tmp_v[] = $v['content']?:" ";
                    $tmp_v[] = $actionnm[$v['actionnm']]?:" ";
                    $tmp_v[] = $fromid?:" ";
                    $tmp_v[] = $tolist?:" ";
                    $tmp_v[] = $v['msgtime']?:" ";
                    mb_convert_variables('GBK', 'UTF-8', $tmp_v);
                    fputcsv($fp, $tmp_v);//将数据格式化为csv格式并写入到output流中
                }
                ob_flush();
                flush();//刷新输出缓冲到浏览器，使用效果是可以立即关闭新开页面，不用等待，只需要等待下载即可
                fclose($fp);
            }else{
                $list = Db::table($firstsql . 'as msg')->order($order)->paginate($limit)->each(function ($item){
                    $tmp_user = User::where('userid','in',$item['tolist'])->column('name');
                    $tmp_cust = Cust::where('external_userid','in',$item['tolist'])->column('name');
                    $item['tolist_names'] = array_merge($tmp_user,$tmp_cust);
                    return $item;
                })->toArray();
                return success_json('成功',$list);
            }

        }

    }


    /**获取聊天上下文
     * @param $data
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getChatContext($data,$admin_groupid,$adminid)
    {
        $limit = $data['limit']?:config('page.defaule_limit');
        if(!$data['group_id']) return error_json('参数错误'); if(!$data['msgid']) return error_json('参数错误');
        $group_id = $data['group_id'];

        //有权限的所有成员
        $hsorganizationService = new HsorganizationService();
        $auth_user_arr = $hsorganizationService->getDepartmentLst(2,0,$admin_groupid,$adminid);
        if(($auth_user_arr !== 'all') && empty($auth_user_arr)) return error_json('暂无成员权限');
        //查询单条数据
        $this_msg = self::getChatInfo($data,true);
        if(empty($this_msg)) return error_json('记录不存在');
        //查询所有记录表
        $huihua_tables = HuihuaTables::order('id desc')->select()->toArray();
        if(!$huihua_tables) return error_json('记录表查询为空');

        //获取前后15条
        if($huihua_tables) {
            $first_table_suffix = $huihua_tables[0]['table_suffix'];
            //成员权限
            if(($auth_user_arr !== 'all') && !empty($auth_user_arr) ){
                foreach ($auth_user_arr as $au_user)
                {
                    $whereOr_first[] = "FIND_IN_SET('{$au_user}',msg_$first_table_suffix.`tolist`)";
                    $whereOr_first[] = "msg_$first_table_suffix.fromid = '{$au_user}'";
                }
            }

            $firstsql = HuihuaMsg::suffix("_$first_table_suffix")
                ->field("msg_$first_table_suffix.*,user.name as u_name,user.avatar as u_avatar,cust.name as c_name,cust.avatar as c_avatar")
                ->alias("msg_$first_table_suffix");
            $firstsql_next = clone $firstsql;
            $firstsql_pre = $firstsql->where([["hs_group_id",'=', $group_id],['msgtime','<',$this_msg['msgtime']]]); //前15条
            $firstsql_next = $firstsql_next->where([["hs_group_id",'=', $group_id],['msgtime','>',$this_msg['msgtime']]]); //后15条
            if(isset($whereOr_first)){
                $firstsql_pre = $firstsql_pre->where(implode(' OR ',$whereOr_first));//成员权限
                $firstsql_next = $firstsql_next->where(implode(' OR ',$whereOr_first));//成员权限
            }

            $firstwhere = [];
            $firstwhere[] = ["msg_$first_table_suffix.actionnm", "<>", "recall"]; //不查询消息动作为撤回消息的消息类型,因为撤回消息已在拉取消息时处理过了
            $firstsql_pre = $firstsql_pre->where($firstwhere)
                ->join("user user", "msg_$first_table_suffix.fromid = user.userid", "left")
                ->join("cust cust", "cust.external_userid = msg_$first_table_suffix.fromid", "left");
            $firstsql_next = $firstsql_next->where($firstwhere)
                ->join("user user", "msg_$first_table_suffix.fromid = user.userid", "left")
                ->join("cust cust", "cust.external_userid = msg_$first_table_suffix.fromid", "left");

            foreach ($huihua_tables as $k => $tables) {
                if ($k == 0) continue; //跳过第一个表
                $whereOr_other = []; $where = [];
                //成员权限
                if(($auth_user_arr !== 'all') && !empty($auth_user_arr) ){
                    foreach ($auth_user_arr as $au_user_suffix)
                    {
                        $whereOr_other[] = "FIND_IN_SET('{$au_user_suffix}',msg_{$tables['table_suffix']}.`tolist`)";
                        $whereOr_other[] = "msg_{$tables['table_suffix']}.fromid = '{$au_user_suffix}'";
                    }
                }
                $where[] = ["msg_{$tables['table_suffix']}.actionnm", "<>", "recall"]; //不查询消息动作为撤回消息的消息类型,因为撤回消息已在拉取消息时处理过了
                $sql = HuihuaMsg::suffix("_{$tables['table_suffix']}")
                    ->field("msg_{$tables['table_suffix']}.*,user$k.name as u_name,user$k.avatar as u_avatar,cust$k.name as c_name,cust$k.avatar as c_avatar")
                    ->alias("msg_{$tables['table_suffix']}");
                $sql_next = clone $sql;
                $sql_pre = $sql->where([["hs_group_id",'=', $group_id],['msgtime','<',$this_msg['msgtime']]])->where($where);
                $sql_next = $sql_next->where([["hs_group_id",'=', $group_id],['msgtime','>',$this_msg['msgtime']]])->where($where);
                if(!empty($whereOr_other)){
                    $sql_pre = $sql_pre->where(implode(' OR ',$whereOr_other)); //成员权限
                    $sql_next = $sql_next->where(implode(' OR ',$whereOr_other)); //成员权限
                }
                $sql_pre = $sql_pre->join("user user$k", "msg_{$tables['table_suffix']}.fromid = user$k.userid", "left")
                    ->join("cust cust$k", "cust$k.external_userid = msg_{$tables['table_suffix']}.fromid", "left")
                    ->buildSql();
                $sql_next = $sql_next->join("user user$k", "msg_{$tables['table_suffix']}.fromid = user$k.userid", "left")
                    ->join("cust cust$k", "cust$k.external_userid = msg_{$tables['table_suffix']}.fromid", "left")
                    ->buildSql();
                $firstsql_pre = $firstsql_pre->unionAll($sql_pre);
                $firstsql_next = $firstsql_next->unionAll($sql_next);
            }
            $firstsql_pre = $firstsql_pre->buildSql();
            $firstsql_next = $firstsql_next->buildSql();
            $list_pre = Db::table("$firstsql_pre as msg")->order("msg.msgtime asc")->limit($limit)->select()->toArray();
            $list_next = Db::table("$firstsql_next as msg")->order("msg.msgtime asc")->limit($limit)->select()->toArray();
            $list = [...$list_pre,$this_msg,...$list_next];
            return success_json('成功',$list);
        }

    }

    /**根据消息id获取消息(撤回消息等用)
     * @param $data
     * @param $is_inside
     * @return array|\think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getChatInfo($data,$is_inside = false)
    {
        if(!$data['msgid']) return error_json('参数错误');
        $msgid = $data['msgid'];
        $huihua_tables = HuihuaTables::order('id desc')->select()->toArray();
        $info = [];
        foreach ($huihua_tables as $tables)
        {
            if(!$tables['table_suffix']) continue;
            $info = HuihuaMsg::suffix("_{$tables['table_suffix']}")->field('msg.*,user.name as u_name,user.avatar as u_avatar,cust.name as c_name,cust.avatar as c_avatar')
                ->alias('msg')
                ->where(['msg.msgid'=>$msgid])
                ->join('user user', 'msg.fromid = user.userid', 'left')
                ->join('cust cust', 'cust.external_userid = msg.fromid', 'left')
                ->findOrEmpty()->toArray();
            if($info) break; //找到直接跳出
        }
        if($is_inside === true) return $info; //内部调用
        return success_json('成功',$info);
    }

    /**根据成员和时间获取聊天统计数据
     * @param $c_id
     * @return array
     */
    public static function getBaseData($data)
    {
        $time_type = $data['time_type'] ?: 1;
        $time_type = date('Y-m-d 00:00:00', strtotime("-{$time_type} days"));
        if($data['start_time']) $data['start_time'] = date('Y-m-d',strtotime($data['start_time'])) . ' 00:00:00';
        if($data['end_time']) $data['end_time'] = date('Y-m-d',strtotime($data['end_time'])) . ' 23:59:59';
        if ($data['start_time'] && $data['end_time']) {
            $bgn_time = trim($data['start_time']);
            $end_time = trim($data['end_time']);
        } else {
            $bgn_time = date('Y-m-d 00:00:00', strtotime('+1 days', strtotime($time_type)));
            $end_time = date('Y-m-d H:i:s');
        }
        $userid = User::where('userid','=',$data['userid'])->value('id');
        $huihua_tables = HuihuaTables::order('id desc')->select()->toArray();
        if(!$huihua_tables) return false;
        $first_table_suffix = $huihua_tables[0]['table_suffix'];
        //总聊天条数
        $firstsql = HuihuaMsg::suffix("_$first_table_suffix")->alias("msg_$first_table_suffix")->field("msg_$first_table_suffix.msgid as msgid");
        //新增聊天条数&总聊天数用
        if ($userid) {
            $firstsql = $firstsql->join("user user", "user.userid = msg_$first_table_suffix.fromid")
                ->where("user.id", "=", $userid);
        }
        $addfirstsql = clone $firstsql; //新增数据的sql,新增聊天条数
        //新增聊天条数用
        $addfirstsql = $addfirstsql->whereTime("msg_$first_table_suffix.msgtime", "between", [$bgn_time, $end_time]);
        foreach ($huihua_tables as $k => $tables)
        {
            if($k == 0) continue; //跳过第一个表
            $sql = HuihuaMsg::suffix("_{$tables['table_suffix']}")->alias("msg_{$tables['table_suffix']}")->field("msg_{$tables['table_suffix']}.msgid as msgid");
            if ($userid) {
                $sql = $sql->join("user user$k", "user$k.userid = msg_{$tables['table_suffix']}.fromid")
                    ->where("user$k.id", "=", $userid);
            }
            $addsql = clone $sql; //新增数据的sql
            $sql = $sql->buildSql();
            $firstsql = $firstsql->unionAll($sql);

            //新增数据的sql
            $addsql = $addsql->whereTime("msg_{$tables['table_suffix']}.msgtime", "between", [$bgn_time, $end_time]);
            $addsql = $addsql->buildSql();
            $addfirstsql = $addfirstsql->unionAll($addsql);

        }
        $firstsql =  $firstsql->buildSql();
        $addfirstsql =  $addfirstsql->buildSql();
        $total = Db::table("$firstsql as msg")->count();
        $add = Db::table("$addfirstsql as msg")->count();


        return compact('total', 'add');
    }

    /**根据成员和时间获取聊天数据折线图
     * @return array|false
     */
    public static function getEchatsData($data)
    {
        $time_type = $data['time_type'] ?: 1;
        $time_type = date('Y-m-d 00:00:00', strtotime("-{$time_type} days"));
        $data['start_time'] && $data['start_time'] = date('Y-m-d',strtotime($data['start_time'])) . ' 00:00:00';
        $data['end_time'] && $data['end_time'] = date('Y-m-d',strtotime($data['end_time'])) . ' 23:59:59';
        if ($data['start_time'] && $data['end_time']) {
            $bgn_time = trim($data['start_time']);
            $end_time = trim($data['end_time']);
        } else {
            $bgn_time = date('Y-m-d 00:00:00', strtotime('+1 days', strtotime($time_type)));
            $end_time = date('Y-m-d H:i:s');
        }
        $userid = User::where('userid','=',$data['userid'])->value('id');
        $huihua_tables = HuihuaTables::order('id desc')->select()->toArray();
        if(!$huihua_tables) return false;
        $first_table_suffix = $huihua_tables[0]['table_suffix'];
        //总聊天条数
        $firstsql = HuihuaMsg::suffix("_$first_table_suffix")->alias("msg_$first_table_suffix")->field("msg_$first_table_suffix.msgtime,msg_$first_table_suffix.msgid");
        if ($userid) $firstsql = $firstsql->join("user user", "user.userid = msg_$first_table_suffix.fromid")->where("user.id", "=", $userid);

        $firstsql = $firstsql->whereTime("msg_$first_table_suffix.msgtime","between", [$bgn_time, $end_time]);
        foreach ($huihua_tables as $k => $tables)
        {
            if($k == 0) continue; //跳过第一个表
            $sql = HuihuaMsg::suffix("_{$tables['table_suffix']}")->alias("msg_{$tables['table_suffix']}")->field("msg_{$tables['table_suffix']}.msgtime ,msg_{$tables['table_suffix']}.msgid");
            if ($userid) $sql = $sql->join("user user$k", "user$k.userid = msg_{$tables['table_suffix']}.fromid")->where("user$k.id", "=", $userid);
            $sql = $sql->whereTime("msg_{$tables['table_suffix']}.msgtime", "between", [$bgn_time, $end_time]);
            $sql = $sql->buildSql();
            $firstsql = $firstsql->unionAll($sql);
        }
        $firstsql =  $firstsql->buildSql();
        $add = Db::table("$firstsql as msg")->field("DATE_FORMAT(msg.msgtime,'%Y%m%d') as add_time,count(msg.msgid) as count")->group('add_time')->select()->toArray();
        $add = array_column($add, 'count', 'add_time');
        $add = Date::getChatDateList($bgn_time, $end_time, $add);
        return $add;
    }

}